// Cambridge version with singular updating....
import java.util.Hashtable;

import java.util.Enumeration;
import java.util.Collections;
import java.util.Vector;
import java.util.Random;
import java.awt.Color;
import java.awt.Point;
import EA.*;
import EA.testproblems.*;
import EA.operators.selection.*;
import EA.recording.*;
import RKUjava.datastructures.RKUVector;
import RKUjava.util.*;
import RKUjava.lang.RKUCloneable;
import Visualization.plot.*;
/*
 * @author Lars Bach & Rene Thomsen
 * @version 0.4
 */

public class TwoDimSim implements BatchJobEA {
    
    public static CellIndividual[][] population;
    public static double benefit = 1; //default 
    public static double cost = 1; //default 
    public static double initfreq = 0.19; //default 
    public  int populationsize = 150; //default 
    public double mortality = 0.05; //default
    private static final boolean DEBUG = false;
    public int maxsteps = 500; //default 
    public int updatemethod = 1;
    public int neighborhood = 0;
    private int sleepdelay = 1;
    public int displaygrid = 1;
    private int step = 0;
    
    //GUI
    private GridWorld gridworld;
    
    //results container
    private SequenceTable results;

    //True if the info should be printed to stdout
    public boolean verbose;
    
    public TwoDimSim() {}
    
    private void start() {
	initialise(populationsize);
	summary();
	while (step < maxsteps) {
	    if (verbose) System.out.println("generation = " + step);
	    payoffUpdate();
	    suddenDeath();  
	    reproduction();
	    payoffRecet();
	    summary();
	    if (displaygrid == 1) updateGUI();
	    step++;
	}
    }
    
    private void initialise(int populationsize) {
	population = new CellIndividual[populationsize][populationsize];
	for (int i = 0; i < populationsize; i++) {
	    for (int j = 0; j < populationsize; j++){ 
	  CellIndividual d = new CellIndividual(initfreq);
	  population[i][j] = d;
	    }
	}
	
	if (displaygrid == 1)
	    gridworld = new GridWorld("TumorCell v0.1",this,1,0);
    
	//initialize results table
	results = new SequenceTable("TumorModel");
	results.addColumn(new SequenceTableColumn("Generation"));
	results.addColumn(new SequenceTableColumn("#pluscells"));
	results.addColumn(new SequenceTableColumn("#minuscells"));
    }   
    
    private void payoffUpdate() {
	switch (updatemethod) {
	case 0:
	    if (neighborhood == 0) 
		  Rep2PlayerMoorePayoff();
	    else if (neighborhood == 1) 
		Rep2PlayerNeumannPayoff();
	    break;
	case 1:
	    if (neighborhood == 0) {
		NinePlayerMoorePayoff();
	    } else if (neighborhood == 1) 
		FivePlayerNeumannPayoff();
	    break;
	}
    }

    public void FivePlayerNeumannPayoff() {
	int count;
	for (int i = 0; i<population.length; i++) {
	    for (int j = 0; j<population.length; j++) {                              
		CellIndividual d1 = population[(i-1+population.length)%population.length]
		    [(j)%population.length];
		CellIndividual d2 = population[(i+1+population.length)%population.length]
		    [(j)%population.length];
		CellIndividual d3 = population[(i)%population.length]
		    [(j-1+population.length)%population.length];
		CellIndividual d4 = population[(i)%population.length]
		    [(j+1+population.length)%population.length];
		count = 0;
		if (d1.getCelltype()==1) count++;
		if (d2.getCelltype()==1) count++;
		if (d3.getCelltype()==1) count++;
		if (d4.getCelltype()==1) count++;
		if (population[i][j] != null) {
		    if (population[i][j].getCelltype()==1) {//a cell type 1
			if (count>1) { population[i][j].addtoPayoff((1-cost+benefit));
			}
			else { population[i][j].addtoPayoff((1-cost));
			}
		    }
		    else { // cell type O
			if (count>2) { population[i][j].addtoPayoff
					   (1+benefit);
			}
			else { population[i][j].addtoPayoff(1);
			}
		    }
		}
	    } 
	}
    }
    public void NinePlayerMoorePayoff() {//All sluts should be occupied
	int count;
	if (DEBUG) System.out.println("\ntestPayoffupdate");
        for (int i = 0; i<population.length; i++) {
	    for (int j = 0; j<population.length; j++) {               
		if (DEBUG) 
		    System.out.println("(i,j) = "+i+","+j+" \nneighbours:\n");
		CellIndividual d1 = population[(i-1+population.length)%population.length]
		    [(j)%population.length];
		
		//System.out.println(""+(i-1+pop.length)%pop.length+","+
		//	   (j)%pop.length);
		 
		CellIndividual d2 = population[(i-1+population.length)%population.length]
		    [(j+1+population.length)%population.length];
		
		//System.out.println(""+(i-1+pop.length)%pop.length+","+
		//	   (j+1+pop.length)%pop.length);
		
		CellIndividual d3 = population[(i-1+population.length)%population.length]
		    [(j-1+population.length)%population.length];
		
		//System.out.println(""+(i-1+pop.length)%pop.length+","+
		//	   (j-1+pop.length)%pop.length);
		
		CellIndividual d4 = population[(i+1+population.length)%population.length]
		    [(j)%population.length];
		
		//System.out.println(""+(i+1+pop.length)%pop.length+","+
		//	   (j)%pop.length);
		
		CellIndividual d5 = population[(i+1+population.length)%population.length]
		    [(j+1+population.length)%population.length];
	        
		//System.out.println(""+(i+1+pop.length)%pop.length+","+
		//	   (j+1+pop.length)%pop.length);
		
		CellIndividual d6 = population[(i+1+population.length)%population.length]
		    [(j-1+population.length)%population.length];
		
		//System.out.println(""+(i+1+pop.length)%pop.length+","+
		//	   (j-1+pop.length)%pop.length);
		
		CellIndividual d7 = population[(i)%population.length]
		    [(j+1+population.length)%population.length];
		
		//System.out.println(""+(i)%pop.length+","+
		//		   (j+1+pop.length)%pop.length);
		
		CellIndividual d8 = population[(i)%population.length]
		    [(j-1+population.length)%population.length];
		
		//System.out.println(""+(i)%pop.length+","+
		//	   (j-1+pop.length)%pop.length);
		
		//SELF//CellIndividual d9 = pop[(i)%pop.length]
		//    [(j)%pop.length];
		count =0;
		if (d1.getCelltype()==1){ count++;}
		if (d2.getCelltype()==1){ count++;}
		if (d3.getCelltype()==1){ count++;}
		if (d4.getCelltype()==1){ count++;}
		if (d5.getCelltype()==1){ count++;}
		if (d6.getCelltype()==1){ count++;}	
		if (d7.getCelltype()==1){ count++;}
      		if (d8.getCelltype()==1){ count++;}
		//  if (d9.getCelltype()==1) count++;
		// HERUNDER ** PAYOFF SOM FUNKTION AF HVOR MANGE 1-CELLER DER ER I NEIGHB.	    
		if (population[i][j] != null) {
		    if (population[i][j].getCelltype()==1) {//a cell type 1
			if (count>5) { population[i][j].addtoPayoff((1-cost+(benefit))); 
			}
			else { population[i][j].addtoPayoff((1-cost));
			}
		    }
		    else { // a cell type 0
			//System.out.println("Type is 0");
			if (count>4) { population[i][j].addtoPayoff((1+(benefit)));
			}
			else { population[i][j].addtoPayoff(1);
			//System.out.println("Payoff is 1");
			}
		    }
		    if (DEBUG)
		       	System.out.println("indv: "+i+","+j+" payO: "+population[i][j].getPayoff());
		}
		
	    } 
	}
    }
    public void Rep2PlayerMoorePayoff() {
	for (int i = 0; i<population.length; i++) {
	    for (int j = 0; j<population.length; j++) {                              
		
		CellIndividual d1 = population[(i-1+population.length)%population.length]
		    [(j)%population.length];
		
		//System.out.println(""+(i-1+population.length)%population.length+","+
		//	   (j)%population.length);
		
		CellIndividual d2 = population[(i-1+population.length)%population.length]
		    [(j+1+population.length)%population.length];
		
		//System.out.println(""+(i-1+population.length)%population.length+","+
		//	   (j+1+population.length)%population.length);
		
		CellIndividual d3 = population[(i-1+population.length)%population.length]
		    [(j-1+population.length)%population.length];
		
		//System.out.println(""+(i-1+population.length)%population.length+","+
		//	   (j-1+population.length)%population.length);

		CellIndividual d4 = population[(i+1+population.length)%population.length]
		    [(j)%population.length];

		//System.out.println(""+(i+1+population.length)%population.length+","+
		//	   (j)%population.length);

		CellIndividual d5 = population[(i+1+population.length)%population.length]
		    [(j+1+population.length)%population.length];
	        
		//System.out.println(""+(i+1+population.length)%population.length+","+
		//	   (j+1+population.length)%population.length);

		CellIndividual d6 = population[(i+1+population.length)%population.length]
		    [(j-1+population.length)%population.length];

		//System.out.println(""+(i+1+population.length)%population.length+","+
		//	   (j-1+population.length)%population.length);

		CellIndividual d7 = population[(i)%population.length]
		    [(j+1+population.length)%population.length];
		
		//System.out.println(""+(i)%population.length+","+
		//		   (j+1+population.length)%population.length);

		CellIndividual d8 = population[(i)%population.length]
		    [(j-1+population.length)%population.length];

		//System.out.println(""+(i)%population.length+","+
		//	   (j-1+population.length)%population.length);
		
		//SELF//CellIndividual d9 = population[(i)%population.length]
		//    [(j)%population.length];

 // Two-player game !!!!!
		if (population[i][j] != null) {
		    if(population[i][j].getCelltype()==1) {
			population[i][j].addtoPayoff(8*(1-cost+benefit));
		    }
		    if(population[i][j].getCelltype()==0) {
			if( d1.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			}
			if( d2.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			} 
			if( d3.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			} 
			if( d4.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			}
			if( d5.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			}
			if( d6.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			} 
			if( d7.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			} 
			if( d8.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			} 
		    }
		}
		if (DEBUG)
		    System.out.println("indv: "+i+" payO: "+population[i][j].getPayoff());
	    }
	} 
    }

public void Rep2PlayerNeumannPayoff() {
    double d = benefit;
	for (int i = 0; i<population.length; i++) {
	    for (int j = 0; j<population.length; j++) {                              
		CellIndividual d1 = population[(i-1+population.length)%population.length]
		    [(j)%population.length];
		CellIndividual d2 = population[(i+1+population.length)%population.length]
		    [(j)%population.length];
		CellIndividual d3 = population[(i)%population.length]
		    [(j-1+population.length)%population.length];
		CellIndividual d4 = population[(i)%population.length]
		    [(j+1+population.length)%population.length];
		// repeated two-player- UPDATING !
		//the following is to check a H-D (=BD)
	    
		if (population[i][j] != null) {  // x=0.5 and e=1
		    if(population[i][j].getCelltype()==1) {
			if( d1.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1.0+0.5);//S
				}			    
			else {population[i][j].addtoPayoff(1.0+0.5+1.0);//R
				  }
			if( d2.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1.0+0.5);//S
				}			    
			else {population[i][j].addtoPayoff(1.0+0.5+1.0);//R
				  }
			if( d3.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1.0+0.5);//S
				}			    
			else {population[i][j].addtoPayoff(1.0+0.5+1.0);//R
				  }
			if( d4.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1.0+0.5);//S
				}			    
			else {population[i][j].addtoPayoff(1.0+0.5+1.0);//R
				  }
		    }		    
		    if(population[i][j].getCelltype()==0) {
			if( d1.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1.0);//P
				}			    
			else {population[i][j].addtoPayoff(1.0+d);//T
				  }
			if( d2.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1.0);
				}			    
			else {population[i][j].addtoPayoff(1.0+d);
				  }
			if( d3.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1.0);
				}			    
			else {population[i][j].addtoPayoff(1.0+d);
				  }
			if( d4.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1.0);
				}			    
			else {population[i][j].addtoPayoff(1.0+d);
				  }
		    }
		}	  
		    //normal
		    //		    if(population[i][j].getCelltype()==1) {
		    //	population[i][j].addtoPayoff(4*(1-cost+benefit));
		    //}
			  /*		    if(population[i][j].getCelltype()==0) {
			if( d1.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			}
			if( d2.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
		        else{ population[i][j].addtoPayoff(1+benefit);
			} 
			if( d3.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			} 
			if( d4.getCelltype()==0 ) {
			    population[i][j].addtoPayoff(1);
			}
			else{ population[i][j].addtoPayoff(1+benefit);
			} 
		    }
		}*/
	       if (DEBUG)
		    System.out.println("indv: "+i+" payO: "+population[i][j].getPayoff());
	    }
	} 
    }

    /*    private void suddenDeath() {
	Random rand_i = new Random ();
	//Random rand_j = new Random ();       
	int randindex_i = rand_i.nextInt(population.length);
	int randindex_j = rand_i.nextInt(population.length);
	population[randindex_i][randindex_j]= null;
	if (DEBUG) System.out.println(" cell ("+randindex_i+", "+randindex_j+") is free");
	return;
	}*
    */
    private void suddenDeath() {   
	if (DEBUG) 
	    System.out.println("test random mortality");
	for (int i=0; i<population.length;  i++){
	    for (int j=0; j<population.length; j++){
		if (Math.random() < mortality) {
		    population[i][j]= null;
		    if (DEBUG)
			System.out.println(" cell ("+i+","+j+") is dead!");
		}
	    }
	}
    }
    private void reproduction() {
	switch (updatemethod) {
	case 0:
	    if (neighborhood == 0) 
		  Rep2PlayerMooreReproduction();
	    else if (neighborhood == 1) 
		Rep2PlayerNeumannReproduction();
	    break;
	case 1:
	    if (neighborhood == 0) {
		NinePlayerMooreReproduction();
		//System.out.println("kommer senere...");
		//System.exit(1);
		//pending...
	    } else if (neighborhood == 1) 
		  FivePlayerNeumannReproduction();
	    break;
	}
    }
    public void NinePlayerMooreReproduction(){//assuming that not all neighbours are null.
	String tmpBuffer = new String();
	Vector inputvector = new Vector();
	if (DEBUG)
	    System.out.println("test starting reprd.");
	for (int i = 0; i<population.length; i++) {
	    for (int j = 0; j<population.length; j++){
		if (population[i][j]==null) {// checking celltype is null

	        CellIndividual d0 = new CellIndividual(0); 
		  
		CellIndividual d1 = population[(i-1+population.length)%population.length]
		    [(j)%population.length];
		CellIndividual d2 = population[(i-1+population.length)%population.length]
		    [(j+1+population.length)%population.length];
		CellIndividual d3 = population[(i-1+population.length)%population.length]
		    [(j-1+population.length)%population.length];

		CellIndividual d4 = population[(i+1+population.length)%population.length]
		    [(j)%population.length];
		CellIndividual d5 = population[(i+1+population.length)%population.length]
		    [(j+1+population.length)%population.length];
	        CellIndividual d6 = population[(i+1+population.length)%population.length]
		    [(j-1+population.length)%population.length];

		CellIndividual d7 = population[(i)%population.length]
		    [(j+1+population.length)%population.length];
		CellIndividual d8 = population[(i)%population.length]
		    [(j-1+population.length)%population.length];
		
		/*		System.out.print(" celltype of new C's");
		if (d1 != null){
		    System.out.print("   "+d1.getCelltype());
		    tmpBuffer += " "+d1.getPayoff();
		}
		else{
		    System.out.print("   N");
		    tmpBuffer += "   N";
		}if (d2 != null){
		    System.out.print("   "+d2.getCelltype());
		    tmpBuffer += " "+d2.getPayoff();
		}
		else{
		    System.out.print("   N");
		    tmpBuffer += "   N";
		}if (d3 != null){
		    System.out.print("   "+d3.getCelltype());
		    tmpBuffer += " "+d3.getPayoff();
		}
		else{
		    System.out.print("   N");
		    tmpBuffer += "   N";
		}if (d4 != null){
		    System.out.print("   "+d4.getCelltype());
		    tmpBuffer += " "+d4.getPayoff();
		}
		else{
		    System.out.print("   N");
		    tmpBuffer += "   N";
		}if (d5 != null){
		    System.out.print("   "+d5.getCelltype());
		    tmpBuffer += " "+d5.getPayoff();
		}
		else{
		    System.out.print("   N");
		    tmpBuffer += "   N";
		}if (d6 != null){
		    System.out.print("   "+d6.getCelltype());
		    tmpBuffer += " "+d6.getPayoff();
		}
		else{
		    System.out.print("   N");
		    tmpBuffer += "   N";
		}if (d7 != null){
		    System.out.print("   "+d7.getCelltype());
		    tmpBuffer += " "+d7.getPayoff();
		}
		else{
		    System.out.print("   N");
		    tmpBuffer += "   N";
		}if (d8 != null){
		    System.out.print("   "+d8.getCelltype());
		    tmpBuffer += " "+d8.getPayoff();
		}
		else{
		    System.out.print("   N");
		    tmpBuffer += "   N";
		}
		System.out.print("\n");
		System.out.println(" value of new C's   "+tmpBuffer);
		tmpBuffer = "";
	  */

 //SELF		//CellIndividual d9 = population[(i)%population.length]
		//    [(j)%population.length];
		inputvector.clear();
		inputvector.addElement(d8);
		inputvector.addElement(d7);
		inputvector.addElement(d6);
		inputvector.addElement(d5);
		inputvector.addElement(d4);
		inputvector.addElement(d3);
		inputvector.addElement(d2);
		inputvector.addElement(d1);
;
		//System.out.println("Call newMaxfunkt");
		System.out.flush();
		 CellIndividual dx = newMaxfunkt(inputvector);
		 // System.out.println("End newMaxfunkt");
		System.out.flush();
		    if (dx != null){
			d0.setCelltype(dx.getCelltype());
		      //System.out.println (" celltype of new C "+dx.getCelltype());
		      //System.out.println(" value of new C "+dx.getPayoff());
		    }
		    d0.setPayoff(0);
		    population[i][j]=d0;
		    if (DEBUG)
		       	System.out.println("  i"+i+" Ctype"+d0.getCelltype());
		}
	    }
	}
    }//reproduction
    public void FivePlayerNeumannReproduction() {
	Vector inputvector = new Vector();
	if (DEBUG)
	    System.out.println("test starting reprd.");
	for (int i = 0; i<population.length; i++) {
	    for (int j = 0; j<population.length; j++){
		if (population[i][j]==null) {
		    CellIndividual d0 = new CellIndividual(1); 
		    	                                            
		    CellIndividual d1 = population[(i-1+population.length)%population.length]
			[(j)%population.length];
		    CellIndividual d2 = population[(i+1+population.length)%population.length]
			[(j)%population.length];
		    CellIndividual d3 = population[(i)%population.length]
			[(j-1+population.length)%population.length];
		    CellIndividual d4 = population[(i)%population.length]
			[(j+1+population.length)%population.length];

		    inputvector.clear();
		    inputvector.addElement(d1);
		    inputvector.addElement(d2);
		    inputvector.addElement(d3);
		    inputvector.addElement(d4);
		    
		    CellIndividual dx = newMaxfunkt(inputvector);
		   
		    if (dx != null)
			d0.setCelltype(dx.getCelltype());
		    d0.setPayoff(0);
		    population[i][j]=d0;
		    if (DEBUG)
			System.out.println("  i"+i+" Ctype"+d0.getCelltype());
		}
	    }
	}
     }
    
       public void Rep2PlayerMooreReproduction() {
	Vector inputvector = new Vector();
	 String tmpBuffer = new String();
	    if (DEBUG)
		System.out.println("test starting reprd.");
	    for (int i = 0; i<population.length; i++) {
		for (int j = 0; j<population.length; j++){
        	    if (population[i][j]==null) {// checking celltype is null
			
			CellIndividual d0 = new CellIndividual(0); 
			
			CellIndividual d1 = population[(i-1+population.length)%population.length]
			    [(j)%population.length];
			CellIndividual d2 = population[(i-1+population.length)%population.length]
			    [(j+1+population.length)%population.length];
			CellIndividual d3 = population[(i-1+population.length)%population.length]
			    [(j-1+population.length)%population.length];
			
			CellIndividual d4 = population[(i+1+population.length)%population.length]
			    [(j)%population.length];
			CellIndividual d5 = population[(i+1+population.length)%population.length]
			    [(j+1+population.length)%population.length];
			CellIndividual d6 = population[(i+1+population.length)%population.length]
			    [(j-1+population.length)%population.length];
			
			CellIndividual d7 = population[(i)%population.length]
			    [(j+1+population.length)%population.length];
			CellIndividual d8 = population[(i)%population.length]
			    [(j-1+population.length)%population.length];
			
			//CellIndividual d9 = population[(i)%population.length]  SELF**
			//    [(j)%population.length];
			
			/*		System.out.print(" celltype of new C's");
				if (d1 != null){
			        System.out.print("   "+d1.getCelltype());
			        tmpBuffer += " "+d1.getPayoff();
				}
				else{
				System.out.print("   N");
				tmpBuffer += "   N";
				}if (d2 != null){
				System.out.print("   "+d2.getCelltype());
				tmpBuffer += " "+d2.getPayoff();
				}
				else{
				System.out.print("   N");
				tmpBuffer += "   N";
				}if (d3 != null){
				System.out.print("   "+d3.getCelltype());
				tmpBuffer += " "+d3.getPayoff();
				}
				else{
				System.out.print("   N");
				tmpBuffer += "   N";
				}if (d4 != null){
				System.out.print("   "+d4.getCelltype());
				tmpBuffer += " "+d4.getPayoff();
				}
				else{
				System.out.print("   N");
				tmpBuffer += "   N";
				}if (d5 != null){
				System.out.print("   "+d5.getCelltype());
				tmpBuffer += " "+d5.getPayoff();
				}
				else{
				System.out.print("   N");
				tmpBuffer += "   N";
				}if (d6 != null){
				System.out.print("   "+d6.getCelltype());
				tmpBuffer += " "+d6.getPayoff();
				}
				else{
				System.out.print("   N");
				tmpBuffer += "   N";
				}if (d7 != null){
				System.out.print("   "+d7.getCelltype());
				tmpBuffer += " "+d7.getPayoff();
				}
				else{
				System.out.print("   N");
				tmpBuffer += "   N";
				}if (d8 != null){
				System.out.print("   "+d8.getCelltype());
				tmpBuffer += " "+d8.getPayoff();
				}
				else{
				System.out.print("   N");
				tmpBuffer += "   N";
				}
				System.out.print("\n");
				System.out.println(" value of new C's   "+tmpBuffer);
				tmpBuffer = "";
			*/
			inputvector.clear();
			inputvector.addElement(d1);
			inputvector.addElement(d2);
			inputvector.addElement(d3);
			inputvector.addElement(d4);	       
			inputvector.addElement(d5);
			inputvector.addElement(d6);
			inputvector.addElement(d7);
			inputvector.addElement(d8);		
			
		        CellIndividual dx = newMaxfunkt(inputvector); 
			
			if (dx != null){
		            d0.setCelltype(dx.getCelltype());
			    //System.out.println (" celltype of new C "+dx.getCelltype());
			    // System.out.println(" value of new C "+dx.getPayoff());
			}
			d0.setPayoff(0);
			population[i][j]=d0;
			if (DEBUG)
			    System.out.println("  i"+i+" Ctype"+d0.getCelltype());
		    }
		}
	    }
    }
    
    /* public void Rep2PlayerMooreReproduction() {
	//public void reproduction(){//assuming that not both neighbours are null
	Vector inputvector = new Vector();
        String tmpBuffer = new String();	
        double [] payoffAr = new double [8];
	double totalPayoff = 0;
	if (DEBUG)
	    System.out.println("test starting reprd.");
	for (int i = 0; i<population.length; i++) {
	    for (int j = 0; j<population.length; j++){
		if (population[i][j]==null) {
		    CellIndividual d0 = new CellIndividual(0);                       
		    CellIndividual d1 = population[(i-1+population.length)%population.length]
			[(j)%population.length];
		    CellIndividual d2 = population[(i-1+population.length)%population.length]
			[(j+1+population.length)%population.length];
		    CellIndividual d3 = population[(i-1+population.length)%population.length]
			[(j-1+population.length)%population.length];
		    
		    CellIndividual d4 = population[(i+1+population.length)%population.length]
			[(j)%population.length];
		    CellIndividual d5 = population[(i+1+population.length)%population.length]
			[(j+1+population.length)%population.length];
		    CellIndividual d6 = population[(i+1+population.length)%population.length]
			[(j-1+population.length)%population.length];
		    
		    CellIndividual d7 = population[(i)%population.length]
			[(j+1+population.length)%population.length];
		    CellIndividual d8 = population[(i)%population.length]
			[(j-1+population.length)%population.length];
		    
		    inputvector.clear();
		    inputvector.addElement(d1);
		    inputvector.addElement(d2);
		    inputvector.addElement(d3);
		    inputvector.addElement(d4);
		    inputvector.addElement(d5);
		    inputvector.addElement(d6);
		    inputvector.addElement(d7);
		    inputvector.addElement(d8);	
		    //System.out.println(inputvector.toString());
		    totalPayoff = 0;
		    for (int l = 0; l < (inputvector.size()); l++){
			
			//System.out.println(inputvector.size()+"  "+inputvector.elements());
			if (inputvector.elementAt(l) != null && 
			    ((CellIndividual) inputvector.elementAt(l)).getPayoff() != -1){
			    //System.out.println(((CellIndividual)inputvector.elementAt(l)).getPayoff());
			    totalPayoff +=((CellIndividual) inputvector.elementAt(l)).getPayoff();
			} 
		    }
		    
		    // CellIndividual dx = newMaxfunkt(inputvector);        
		    //if (dx != null)
		    //d0.setCelltype(dx.getCelltype());
		    d0.setPayoff(-1);
		    
		    for (int dav=0; dav < payoffAr.length; dav++)
			payoffAr[dav] = 0;
		    
		    if (totalPayoff != 0){
			if(d1!=null && d1.getPayoff() != -1){ 
			    payoffAr[0]=(d1.getPayoff()/totalPayoff);
			}     
			if (d2 != null && d2.getPayoff() != -1){
			    payoffAr[1]=(d2.getPayoff()/totalPayoff);
			}
			if (d3!=null && d3.getPayoff() != -1){
			    payoffAr[2]=(d3.getPayoff()/totalPayoff);
			}
			if (d4!=null && d4.getPayoff() != -1){
			    payoffAr[3]=(d4.getPayoff()/totalPayoff);
			}
			if (d5!=null && d5.getPayoff() != -1){
			    payoffAr[4]=(d5.getPayoff()/totalPayoff);
			}
			if (d6!=null && d6.getPayoff() != -1){    
			    payoffAr[5]=(d6.getPayoff()/totalPayoff);
			}
			if (d7!=null && d7.getPayoff() != -1){
			    payoffAr[6]=(d7.getPayoff()/totalPayoff);
			}
			if (d8!=null && d8.getPayoff() != -1){
			    payoffAr[7]=(d8.getPayoff()/totalPayoff);
			}
			double rand =  Math.random();
			if (rand < payoffAr[0]) {
			    d0.setCelltype(d1.getCelltype());
			}
			else if (rand < (payoffAr[0]+payoffAr[1]) ) {
			    d0.setCelltype(d2.getCelltype());
			}
			else if (rand < (payoffAr[0]+payoffAr[1]+payoffAr[2])) {
			    d0.setCelltype(d3.getCelltype());
			}
			else if (rand < (payoffAr[0]+payoffAr[1]+payoffAr[2]+payoffAr[3])) {
			    d0.setCelltype(d4.getCelltype());
			}
			else if (rand < (payoffAr[0]+payoffAr[1]+payoffAr[2]+payoffAr[3]+payoffAr[4])) {
			    d0.setCelltype(d5.getCelltype());
			}
			else if (rand < (payoffAr[0]+payoffAr[1]+payoffAr[2]+payoffAr[3]+payoffAr[4]+payoffAr[5])) {
			    d0.setCelltype(d6.getCelltype());
			}
			else if (rand < (payoffAr[0]+payoffAr[1]+payoffAr[2]+payoffAr[3]+payoffAr[4]+payoffAr[5]+payoffAr[6])) {
			    d0.setCelltype(d7.getCelltype());
			}
			else {
			    if (d8 == null){
				System.out.println("Rand "+rand+" Accu "+
						   (payoffAr[0]+payoffAr[1]+payoffAr[2]+payoffAr[3]+payoffAr[4]+payoffAr[5]+payoffAr[6]+payoffAr[7])+
						   " Total "+totalPayoff  );
				System.out.println("This should not happend");
				System.exit(1);
			    }
			    d0.setCelltype(d8.getCelltype());
			}
			if (DEBUG)
			    System.out.println("  i"+i+" Ctype"+d0.getCelltype());
		    }else{
			// DEBUG START
			if (d1 != null){
			    if (d1.getPayoff() != -1)
				System.out.println("##### ##### OEV OEV");
			}
			else if(d2 != null){
			    if (d2.getPayoff() != -1)
				System.out.println("##### #### OEV OEV");
			}
			else if (d3 != null){
			    if (d3.getPayoff() != -1)
				System.out.println("#### ###### OEV OEV");
			}
			else if (d4 != null){
			    if (d4.getPayoff() != -1)
				System.out.println("##### #### OEV OEV");
			}
			if (d5 != null){
			    if (d5.getPayoff() != -1)
				System.out.println("#### ##### OEV OEV");
			}
			else if(d6 != null){
			    if (d6.getPayoff() != -1)
				System.out.println("#### ###### OEV OEV");
			}
			else if (d7 != null){
			    if (d7.getPayoff() != -1)
				System.out.println("#### ###### OEV OEV");
			}
			else if (d8 != null){
			    if (d8.getPayoff() != -1)
				System.out.println("### ###### OEV OEV");
			}
			else
			    System.out.println("All neigthbours are dead");
			//DEBUG END
			
			d0.setCelltype(0);
		    }
		    population[i][j]=d0;
		}
	    }
	}
    }//reproduction--MontpVersion 
    */ 
   
        public void Rep2PlayerNeumannReproduction() {
        Vector inputvector = new Vector();
        if (DEBUG)
            System.out.println("test starting reprd.");
	for (int i = 0; i<population.length; i++) {
            for (int j = 0; j<population.length; j++){
        	if (population[i][j]==null) {
        	    CellIndividual d0 = new CellIndividual(0); 
		    	                                            
		    CellIndividual d1 = population[(i-1+population.length)%population.length]
			[(j)%population.length];
		    CellIndividual d2 = population[(i+1+population.length)%population.length]
			[(j)%population.length];
		    CellIndividual d3 = population[(i)%population.length]
			[(j-1+population.length)%population.length];
		    CellIndividual d4 = population[(i)%population.length]
		        [(j+1+population.length)%population.length];
		    inputvector.clear();
		    inputvector.addElement(d1);
		    inputvector.addElement(d2);
		    inputvector.addElement(d3);
		    inputvector.addElement(d4);
		    CellIndividual dx = newMaxfunkt(inputvector);        
		    if (dx != null){
		        d0.setCelltype(dx.getCelltype());
		    }
		    else {d0.setCelltype(0);}
		    d0.setPayoff(0);
		    population[i][j]=d0;
		    if (DEBUG)
		        System.out.println("  i"+i+" Ctype"+d0.getCelltype());
		}
	//      }
//  	}
    }
	}
	}
    
    /* public void Rep2PlayerNeumannReproduction() {// PROBABILISTIC replacement reproduction
	//        public void reproduction(){//assuming that not both neighbours are null.
	Vector inputvector = new Vector();
	double [] payoffAr = new double [4];
	double totalPayoff = 0;
	if (DEBUG)
	    System.out.println("test starting reprd.");
	for (int i = 0; i<population.length; i++) {
	    for (int j = 0; j<population.length; j++){
		if (population[i][j]==null) {
		    CellIndividual d0 = new CellIndividual(0); 
		    	                                            
		    CellIndividual d1 = population[(i-1+population.length)%population.length]
			[(j)%population.length];
		    CellIndividual d2 = population[(i+1+population.length)%population.length]
			[(j)%population.length];
		    CellIndividual d3 = population[(i)%population.length]
			[(j-1+population.length)%population.length];
		    CellIndividual d4 = population[(i)%population.length]
			[(j+1+population.length)%population.length];
		    inputvector.clear();
		    inputvector.addElement(d1);
		    inputvector.addElement(d2);
		    inputvector.addElement(d3);
		    inputvector.addElement(d4);
		    //System.out.println(inputvector.toString());
		    totalPayoff = 0;
		    for (int l = 0; l < (inputvector.size()); l++){
			
			//System.out.println(inputvector.size()+"  "+inputvector.elements());
			if (inputvector.elementAt(l) != null && 
			    ((CellIndividual) inputvector.elementAt(l)).getPayoff() != -1){
			    //System.out.println(((CellIndividual)inputvector.elementAt(l)).getPayoff());
			    totalPayoff +=((CellIndividual) inputvector.elementAt(l)).getPayoff();
			} 
		    }
		    		    
		    // CellIndividual dx = newMaxfunkt(inputvector);        
		    //if (dx != null)
		    //d0.setCelltype(dx.getCelltype());
		    d0.setPayoff(-1);
		    
		    for (int dav=0;dav < payoffAr.length ; dav++)
			payoffAr[dav] = 0;
		      
		    if (totalPayoff != 0){
			if(d1!=null && d1.getPayoff() != -1){ 
			    payoffAr[0]=(d1.getPayoff()/totalPayoff);
			}     
			if (d2 != null && d2.getPayoff() != -1){
			    payoffAr[1]=(d2.getPayoff()/totalPayoff);
			}
			if (d3!=null && d3.getPayoff() != -1){
			    payoffAr[2]=(d3.getPayoff()/totalPayoff);
			}
			if (d4!=null && d4.getPayoff() != -1){
			    payoffAr[3]=(d4.getPayoff()/totalPayoff);
			}
		    
			double rand =  Math.random();
			if (rand < payoffAr[0]) {
			    d0.setCelltype(d1.getCelltype());
			}
			else if (rand < (payoffAr[0]+payoffAr[1]) ) {
			    d0.setCelltype(d2.getCelltype());
			}
			else if (rand < (payoffAr[0]+payoffAr[1]+payoffAr[2])) {
			    d0.setCelltype(d3.getCelltype());
			}
			else {
			    if (d4 == null){
				System.out.println("Rand "+rand+" Accu "+
						   (payoffAr[0]+payoffAr[1]+payoffAr[2])+
						   " Total "+totalPayoff  );
				System.out.println("This should not happend");
				System.exit(1);
			    }
			    d0.setCelltype(d4.getCelltype());
			}
			if (DEBUG)
			    System.out.println("  i"+i+" Ctype"+d0.getCelltype());
		    }else{
			// DEBUG START
			if (d1 != null){
			    if (d1.getPayoff() != -1)
				System.out.println("#######  OEV OEV OEV");
			}
			else if(d2 != null){
			    if (d2.getPayoff() != -1)
				System.out.println("####### OEV OEV OEV");
			}
			else if (d3 != null){
			    if (d3.getPayoff() != -1)
				System.out.println("####### OEV OEV OEV");
			}
			else if (d4 != null){
			    if (d4.getPayoff() != -1)
				System.out.println("###### OEV OEV OEV");
			}
			else
			    System.out.println("All neigthbours are dead");
			//DEBUG END
			
			d0.setCelltype(0);
		    }
		    population[i][j]=d0;
		}
	    }
	}
	}//probablistic replacement reproduction
    */  
	    private void payoffRecet() {
	for(int i=0; i < population.length; i++){
	    for (int j=0; j<population.length; j++){
		CellIndividual d = population[i][j];
		if (d != null)
		    d.setPayoff(0);
	    }
	}
    }
    
    private void summary() {
	int pluscells = 0;
	double freqOfpluscells = 0;
	float totalcellsalive =0;
	for (int i=0; i<population.length; i++){
	    for (int j =0; j<population.length; j++){
		CellIndividual d = population[i][j];
		if (d != null) {
		    if (d.getCelltype()==1){
			pluscells ++;
		    } else{}
		    totalcellsalive++;
		    freqOfpluscells = (double)(pluscells / totalcellsalive );
		}
	    }
	}
	if (DEBUG)
	    System.out.println("\n*****-- freq of +cells: "+freqOfpluscells);
	
	results.initializeRow();
	results.updateLastRow(0,step); 
	results.updateLastRow(1,freqOfpluscells); //freq of + cells
	results.updateLastRow(2,0); //freq of - cells
	//  	results.updateLastRow(2+curproblem.dimensions, PopulationMeasurements.calcMean(population));
//  	results.updateLastRow(3+curproblem.dimensions, PopulationMeasurements.calcStandardDeviation(population));
    }

   //   private CellIndividual maxNeigh(CellIndividual dA, CellIndividual dB){ 
//  	if (dA == null) return dB;
//  	if (dB == null) return dA;
//  	if (dA.getPayoff() > dB.getPayoff()) { 
//  	    return dA;
//  	}
//  	return dB;
//      }

    public CellIndividual newMaxfunkt (Vector inputvector){
	Random rand = new Random ();
	Vector outputvector = new Vector();
	double tmpmax = -1.0;
	int tmpindex;
	//	System.out.println("Start");
	if (inputvector == null)
	    return null;
	for(int i=0; i<inputvector.size(); i++){
	    if((inputvector.elementAt(i) != null) && 
	       (tmpmax < ((CellIndividual) inputvector.elementAt(i)).getPayoff()) ){
		//System.out.println("1. if");
		outputvector.clear();
		outputvector.addElement(inputvector.elementAt(i));
		tmpmax = ((CellIndividual) inputvector.elementAt(i)).getPayoff();
	    }     
	    else if ((inputvector.elementAt(i) != null) && 
		    (tmpmax == ((CellIndividual) inputvector.elementAt(i)).getPayoff()) ){
		// System.out.println("2. if");
		System.out.flush();
		 outputvector.addElement(inputvector.elementAt(i));
	    }
	}
	if(outputvector.size()==0)
	    return null;
	tmpindex = rand.nextInt(outputvector.size());
	return (CellIndividual)outputvector.elementAt(tmpindex);
	
	// .nextInt(int) returns a uniformly distr. int [0;int]
	// .size returns number of components in this vector.	
    }

    private void updateGUI() {
	gridworld.update();
    }
    
 // **** BatchJob implementation *****************************
    
    /** Set the settings for the algorithm. The passed hashtable contains
	only String objects which are all related to the input file given 
	to the scheduler. 
    */
    public void setSettings(Hashtable settings) {
	String curstr;
	
	if ((curstr = (String)settings.get("verbose"))!=null) 
	    verbose = (new Boolean(curstr)).booleanValue();
	    
	if ((curstr = (String)settings.get("maxsteps"))!=null) 
  	    maxsteps = (new Integer(curstr)).intValue();
	    
	if ((curstr = (String)settings.get("mortality"))!=null) 
	    mortality = (new Double(curstr)).doubleValue();
	
	if ((curstr = (String)settings.get("initfreq"))!=null) 
	    initfreq = (new Double(curstr)).doubleValue();
	
	if ((curstr = (String)settings.get("cost"))!=null) 
	    cost = (new Double(curstr)).doubleValue();

	if ((curstr = (String)settings.get("benefit"))!=null) 
	    benefit = (new Double(curstr)).doubleValue();
	
	if ((curstr = (String)settings.get("updatemethod"))!=null)
	    updatemethod = (new Integer(curstr)).intValue();
	
	if ((curstr = (String)settings.get("neighborhood"))!=null)
	    neighborhood = (new Integer(curstr)).intValue();
	
  	if ((curstr = (String)settings.get("populationsize"))!=null) 
  	     populationsize = (new Integer(curstr)).intValue();
	    
  	if ((curstr = (String)settings.get("displaygrid"))!=null) 
  	    displaygrid = (new Integer(curstr)).intValue();
	}
    
    /** Get the default settings in the BatchJobScheduler format. This 
	method can be used to reconstruct an input file for the scheduler. 
    */
    public String getDefaultSettings() {
	return "";
    }
    
    /** Initialize a batchjob. This is called once before any run is performed.
     */
    public void initializeBatchJobs() {}
    
    /** Finalize a batchjob. This is called once after all runs are performed.
     */
    public void finalizeBatchJobs() {}
    
    /** Initialize a run series. This is called once before the specified 
	number of runs are performed. (BJSruns in the batchfile)
    */
    public void initializeRunSeries() {}
    
    /** Finalize a run series. This is called once after the specified 
	number of runs are performed. (BJSruns in the batchfile)
    */
    public void finalizeRunSeries() {}
    
    /** Initialize and start a single run of the algorithm. You can 
	usually just call doEA() from your framework.
    */
    public void initializeAndStartRun() {
	start();
    }
    
    /** Finalize the single run of the algorithm. This is called immediately
	after the initializeAndStartRun(). It can be used to reset 
	measurements, increase counters, etc.
    */
    public void finalizeRun() {
	//  switch(displaygraph){ 
//  	case 0: // Do nothing
//  	    break;
//  	case 1:
//  	    // curplotter.updatePlot();
//  	    break;
//  	}
    }
    
    /** Get the run data as text. Your implementation must return
	an array of objects that each implements the interface ConvertToText from the package
	EA.recording. You can use the classes found in EA.recording or 
	implement your own classes.
	@see EA.recording.ResultSet
	@see EA.recording.Measurement
	@see EA.recording.ConvertToText
    */
    public Object[] getDataAsText() {
	Object[] res = new Object[1];
	res[0] = results;
	return res;
    }
    
    // ************* Plot interface **********************************
    
    /** Extract the data as a 2 dimensional array of objects. <br>
	<b>Note:</b> All second-indexes arrays must have equal length.
    */
    public synchronized Object[][] extract2DAsObjects(int plotternumber) {
	Object[][] res = new Object[2][0];
	//  switch (plotternumber) {
//  	case 0:
//  	    res[0] = (results.getColumn(1)).getDataAsArray();
//  	    res[1] = (results.getColumn(2+curproblem.dimensions)).getDataAsArray();
//  	    break;
//  	case 1:
//  	    res[0] = (results.getColumn(2)).getDataAsArray();
//  	    res[1] = (results.getColumn(3)).getDataAsArray();
//  	    break;
//  	}	    
	return res;
    }
    
    /** Extract the data as a 2 dimensional array of doubles.<br>
	<b>Note:</b> All second-indexes arrays must have equal length. */
    public synchronized double[][] extract2DAsDoubles(int plotternumber) {
	return null;
    };
    
    int[][] resultstypes = {{0,0},{0,0}};
    int[][] trajectorytypes = {{2,0},{2,0}};
    
    public synchronized int[][] extract2DDataTypes(int plotternumber) {
	switch(plotternumber) {
	case 0:
	    return resultstypes;
	case 1: 
	    return trajectorytypes;
	}
	return resultstypes;
    }
    
    /** Extract the name of a graph given an index. */
    public String extract2DName(int index, int plotternumber) {
	switch (plotternumber) {
	case 0:
	    switch(index) {
	    case 0:
		return "Bestfit";
	    case 1:
		return "Mean";
	    }
	    break;
	case 1:
	    return "Best pos";
	}
	return "";
    }
    
}
